//
//  KKBaseNetMode.m
//  AFnetWorking测试
//
//  Created by long on 14-11-18.
//  Copyright (c) 2014年 谭启龙. All rights reserved.
//

#import "XLBaseNetMode.h"
#import <objc/runtime.h>

typedef enum : NSUInteger {
    ModeDealStyleStrongDebug = 1, //强Debug模式,如果数据类型和后台不一样,或者参数少了则会报错
    ModeDealStyleGeneralDebug, //普通Debug模式,参数少了会报错
    ModeDealStyleDebug, //Debug模式,如果数据映射的参数个数少了不够会提醒单不报错
    ModeDealStyleRelease, //发布版本什么也不处理
} ModeDealStyle;

@interface XLBaseNetMode ()
{
    ModeDealStyle _modeDealStyle;
}
@end

@implementation XLBaseNetMode

-(id)initWithDataDic:(NSDictionary *)data
{
    if (self = [super init]) {
        _modeDealStyle = ModeDealStyleRelease;
        [self setAttributes:data];
        self.originData = data;
    }
    return self;
}

//通过字典映射的方法设置属性的Setter方法
-(SEL)getSetterSelWithAttributeName:(NSString*)attributeName
{
    //首字母大写
    NSString * capital = [[attributeName substringToIndex:1] uppercaseString];
    NSString * setterSelStr = [NSString stringWithFormat:@"set%@%@:",capital,[attributeName substringFromIndex:1]];
    return NSSelectorFromString(setterSelStr);
}

-(void)setAttributes:(NSDictionary *)dataDic
{
    //获取映射的字典
    NSDictionary * attriMapDic = [self attributeMapDictionary];
    if (attriMapDic == nil || ![dataDic isKindOfClass:[NSDictionary class]]) {
        return;
    }
    //枚举便利
    NSEnumerator * keyEnum = [attriMapDic keyEnumerator];
    id key;
    while ((key = [keyEnum nextObject])) {
        //通过映射写好setter
        SEL sel = [self getSetterSelWithAttributeName:key];
        if ([self respondsToSelector:sel]) {
            //获取json名字的字段取得值写入setter
            NSString * dataDicKey = attriMapDic[key];
            if (![[dataDic allKeys]containsObject:dataDicKey]) {
                //如果没有对应的映射则不做处理
                continue;
            }
            //查询自身属性类型
            char * pStr = (char *)[key UTF8String];
            objc_property_t property = class_getProperty([self class], pStr);
            const char * attributeTypeChar = property_getAttributes(property);
            
            NSMethodSignature * sig = [[self class] instanceMethodSignatureForSelector:sel];
            const char * str = [sig getArgumentTypeAtIndex:2];
//            NSLog(@"%s",str);
            AttributeType attributeType = [self checkAttributeType:attributeTypeChar];
            NSInvocation * invocation = [NSInvocation invocationWithMethodSignature:sig];
            [invocation setTarget:self];
            [invocation setSelector:sel];
            //根据属性类型 映射接口值
            id value = [dataDic objectForKey:dataDicKey];
            if (value == nil) {
                //强Debug 和 普通debug模式 参数缺失会报错
                if (_modeDealStyle == ModeDealStyleStrongDebug || _modeDealStyle == ModeDealStyleGeneralDebug) {
                    NSString * str = [NSString stringWithFormat:@"类%@参数%@缺失",[self class],dataDicKey];
                    NSAssert(NO,str);
                }
                //开发模式会提示但不报错
                else if (_modeDealStyle == ModeDealStyleDebug) {
                    NSString * str = [NSString stringWithFormat:@"类%@参数%@缺失",[self class],dataDicKey];
                    NSLog(@"%@",str);
                }
            }
            switch (attributeType) {
                case AttributeType_NSString:
                    if ([value isKindOfClass:[NSNumber class]]) {
                        //接口值类型为Number
                        NSString * strValue = [value stringValue];
                        [invocation setArgument:&strValue atIndex:2];
                        [invocation retainArguments];
                        if (_modeDealStyle == ModeDealStyleStrongDebug) {
                            NSString * str = [NSString stringWithFormat:@"类%@参数%@与后台类型不匹配",[self class],dataDicKey];
                            NSAssert(NO, str);
                        }
                    } else if ([value isKindOfClass:[NSString class]]) {
                        //接口值类型为String
                        [invocation setArgument:&value atIndex:2];
                        [invocation retainArguments];
                    }
                    break;
                case AttributeType_NSNumber:
                    if ([value isKindOfClass:[NSNumber class]]) {
                        [invocation setArgument:&value atIndex:2];
                        [invocation retainArguments];
                    } else if ([value isKindOfClass:[NSString class]]) {
                        NSNumber * number = [NSNumber numberWithFloat:[value floatValue]];
                        [invocation setArgument:&number atIndex:2];
                        [invocation retainArguments];
                        if (_modeDealStyle == ModeDealStyleStrongDebug) {
                            NSString * str = [NSString stringWithFormat:@"类%@参数%@与后台类型不匹配",[self class],dataDicKey];
                            NSAssert(NO, str);
                        }
                    }
                    break;
                case AttributeType_Int:
                {
                    int intValue = [value intValue];
                    [invocation setArgument:&intValue atIndex:2];
                    [invocation retainArguments];
                }
                    break;
                case AttributeType_Long:
                {
                    long longValue = [value longLongValue];
                    [invocation setArgument:&longValue atIndex:2];
                    [invocation retainArguments];
                }
                    break;
                case AttributeType_Float:
                {
                    float floatValue = [value floatValue];
                    [invocation setArgument:&floatValue atIndex:2];
                    [invocation retainArguments];
                }
                    break;
                case AttributeType_Double:
                {
                    double doubleValue = [value doubleValue];
                    [invocation setArgument:&doubleValue atIndex:2];
                    [invocation retainArguments];
                }
                    break;
                case AttributeType_Bool:
                {
                    BOOL boolValue = [value boolValue];
                    [invocation setArgument:&boolValue atIndex:2];
                    [invocation retainArguments];
                }
                    break;
                case AttributeType_Object:
                {
                    [invocation setArgument:&value atIndex:2];
                    [invocation retainArguments];
                }
                    break;
                default:
                {
                    NSString * des = [NSString stringWithFormat:@"类%@ %@属性类型与约定的属性类型不符 详情请看类%@枚举支持的属性映射类型",[self class],key,[self class]];
                    NSAssert(NO, des);
                }
                    break;
            }
            if (_modeDealStyle == ModeDealStyleStrongDebug) {
                if (attributeType != AttributeType_NSString && attributeType != AttributeType_NSNumber) {
                    NSString * str = [NSString stringWithFormat:@"类%@参数%@与后台类型不匹配",[self class],dataDicKey];
                    NSAssert(NO, str);
                }
            }
            [invocation invoke];
//            //判断value是什么类型
//            if ([dataDic isKindOfClass:[NSDictionary class]]) {
//                if ([[dataDic objectForKey:dataDicKey] isKindOfClass:[NSNumber class]]) {
//                    value = [dataDic objectForKey:dataDicKey];
//                }
//                else if ([[dataDic objectForKey:dataDicKey]isKindOfClass:[NSNull class]])
//                {
//                    value = nil;
//                }
//                else if ([[dataDic objectForKey:dataDicKey]isKindOfClass:[NSString class]])
//                {
//                    value = [dataDic objectForKey:dataDicKey];
//                }
//                else
//                {
//                    value = [dataDic objectForKey:dataDicKey];
//                }
//            }
//            //执行方法，必须要保证子类有该属性才行
//            [self performSelectorOnMainThread:sel withObject:value waitUntilDone:[NSThread isMainThread]];
        }
    }
}

//检测属性类型
/*
 属性映射表规范:
 int  Ti
 u_int TI
 long Tq
 u_long TQ
 float Tf
 double Td
 NSString T@"NSString"
 NSNumber T@"NSNumber"
 */
-(AttributeType)checkAttributeType:(const char *)typeStr {
    if (typeStr == nil) {
        return AttributeType_UnKnow;
    }
    switch (typeStr[1]) {
        case 'i':
            return AttributeType_Int;
            break;
        case 'I':
            return AttributeType_Int;
            break;
        case 'q':
            return AttributeType_Long;
            break;
        case 'Q':
            return AttributeType_Long;
            break;
        case 'f':
            return AttributeType_Float;
            break;
        case 'd':
            return AttributeType_Double;
            break;
        case 'B':
            return AttributeType_Bool;
        case '@':
            if (typeStr[5] == 'N') {
                return AttributeType_NSNumber;
            } else if (typeStr[5] == 'S') {
                return AttributeType_NSString;
            } else {
                return AttributeType_Object;
            }
        default:
            return AttributeType_UnKnow;
            break;
    }
}

//映射属性赋值
#pragma mark 让子类重写的方法
-(NSDictionary *)attributeMapDictionary
{
    NSLog(@"==============类%@没有重写属性映射表==============",[self class]);
    return nil;
}
@end
